; Length is the same as count
(defmacro length (list) `(count list))
; Append is the same as cons
(defmacro append (l1 l2) `(cons l1 l2))
; First is the same as car
(defmacro first (list) `(car list))
; Rest is the same as cdr
(defmacro rest (list) `(cdr list))

; Defines the fold function (right-associative fold)
(defun fold (f end l) (if (nil? l)
                            end
                            (f (car l) (fold f end (cdr l)))))

; Defines the fold function (left-associative fold)
(defun reduce (f acc l) (if (nil? l)
                          acc
                          (reduce f (f acc (car l)) (cdr l))))
              
; Defines filter function
(defun filter (criteria list) (fold (lambda (x y) (if (criteria x) (cons x y) y)) nil list))

; Defines max function
(defun max (l) (reduce (lambda (old new) (if (> old new) old new)) (car l) (cdr l)))

; Defined min function
(defun min (l) (reduce (lambda (old new) (if (< old new) old new)) (car l) (cdr l)))

; car returns the first element of a list
(defun car (l) (nth 0 l)) ; Finally decided to name it car as most of the well known lisp dialects

; Last returns the last element of a list
(defun last (l) (nth (- (count l) 1) l))

; cdr returns all the list without the first element
(defun cdr (l) (let ((i 0) (len (count l)))
                    (while (< i (- len 1))
                           (begin (set i (+ i 1))
                                  (nth i l))))) ; Note that while returns a list with the results it generates

; Defines set-cdr!
(defmacro set-cdr! (x y)
				   `(set x (cons (car x) y)))
; Defines set-car!
(defmacro set-car! (x y)
				   `(set x (cons y (cdr x))))

; Defines nthcdr (applies cdr n times)
(defun nthcdr (n l) (if (= n 1)
						 (cdr l)
						 (cdr (nthcdr (- n 1)))))

; Defines cons (yeah i know my method sucks...right? :p)
(defun cons (l1 l2) `(,@l1 ,@l2))
               
; Defines reverse (reverses a list)
(defun reverse (l) (let ((i (count l)))
                        (while (not (zero? i))
                               (begin (set i (- i 1))
                                      (nth i l)))))

; map applies a function to each element of a list, and returns a list with the results of each of these appliances
(defun map (f l) (let ((i -1) (len (count l)))
                      (while (< i (- len 1))
                             (begin (set i (+ i 1))
                                    (f (nth i l))))))
        
